import { getAuthors } from '@/models';
import { gfetch, pfetch } from '@/utils/back/fetch';
import { pickData } from '@/utils/common';
import { cookies, headers } from 'next/headers';
import { NextRequest, NextResponse } from 'next/server';
import { catalogSearchDataCallback } from './category';
import { getProductDetail, getProductList } from './product';

const DSZ_API_DOMAIN = process.env.NEXT_PUBLIC_DSZ_API_DOMAIN!;
const DSZ_DOMAIN = process.env.NEXT_PUBLIC_DSZ_DOMAIN!;

function toJsonResponse(data: any) {
  const format = (data: any): APIRes => {
    if ('success' in data) {
      return data as APIRes;
    }

    return {
      data,
      success: true,
      message: 'ok',
    };
  };
  // return NextResponse.json(format(data));
  return format(data);
}

function getHandler(
  api: string,
  domain: string,
  dataCallback?: Fn,
  errorCallback?: Fn
) {
  return async function (request: NextRequest) {
    const { searchParams } = request.nextUrl;

    const headerData = {} as Obj;
    request.headers.forEach((value, name) => {
      headerData[name] = value;
    });

    const paramsSize = Array.from(searchParams.values()).length;
    const res = await gfetch<Obj>(
      domain + api + (paramsSize ? '?' : '') + searchParams.toString(),
      {
        headers: pickData(headerData, [
          'cookie',
          'accept',
          'accept-encoding',
          'cache-control',
        ]),
        // headers: {},
      }
    );

    if (res.success) {
      if (dataCallback) res.data = dataCallback(res.data);
    } else {
      if (errorCallback) errorCallback(res);
    }

    return toJsonResponse(res);
  };
}

function postHandler(api: string, domain: string, dataCallback?: Fn) {
  return async function (request: NextRequest) {
    const { searchParams } = request.nextUrl;
    const body = await request.text();

    // const pdata = await request.json() || await request.formData();
    const headersObj = headers();
    const headerData = {} as Obj;
    headersObj.forEach((value, name) => {
      headerData[name] = value;
    });

    const paramsSize = Array.from(searchParams.values()).length;
    const res = await pfetch(
      domain + api + (paramsSize ? '?' : '') + searchParams.toString(),
      {
        body,
        // headers: request.headers,
        headers: pickData(headerData, [
          'cookie',
          'accept',
          'accept-encoding',
          'cache-control',
        ]),
      }
    );

    if (res.success && dataCallback) {
      res.data = dataCallback(res.data);
    }

    return toJsonResponse(res);
  };
}

type APIConf = {
  domain?: string;
  api?: string;
  needLogin?: boolean;
  handler?: (request: NextRequest) => Promise<Obj>;
  dataCallback?: Fn;
  errorCallback?: Fn;
  publicAPI?: string;
  privateAPI?: string;
};

const HANDLERS = {
  GET: {
    '/example/rename-api': {
      domain: DSZ_API_DOMAIN,
      api: '/example/real-api',
    },
    '/example/default-domain': {
      api: '/example/real-api',
    },
    '/example/real-api': {},

    // -----------------------------------

    '/private/products': {
      domain: DSZ_API_DOMAIN,
      // api: '/v2/products',
      api: '/public/products',
      needLogin: true,
      handler: null as null | Fn,
      errorCallback: null as null | Fn,
    },
    '/public/products': {
      domain: DSZ_API_DOMAIN,
      // api: '/public/products',
      api: '/public/products',
      handler: null as null | Fn,
    },
    '/end/products': {
      publicAPI: '/public/products',
      privateAPI: '/private/products',
    },
    '/v2/categories/count': {},
    '/product/detail/*': {
      domain: DSZ_API_DOMAIN,
      // handler: getProductDetail,
      api: '/v2/products',
      needLogin: true,
      handler: null as null | Fn,
    },
    '/catalogsearch/ajax/suggest': {
      domain: DSZ_DOMAIN,
      dataCallback: catalogSearchDataCallback,
    },
    '/v2/countries/*': {
      domain: DSZ_API_DOMAIN,
      needLogin: true,
      api: '/v2/countries',
      handler: null as null | Fn,
    },
    '/public/banners': {},
    '/public/trendings': {},
    '/v2/my_sku/get': {
      domain: DSZ_API_DOMAIN,
      api: '/v2/my_sku/get',
      handler: null as null | Fn,
    },
  } as { [key: string]: APIConf },
  POST: {
    '/v2/products': {
      domain: DSZ_API_DOMAIN,
      api: '/v2/products',
    },
    '/v2/my_sku/add': {
      domain: DSZ_API_DOMAIN,
      api: '/v2/my_sku/add',
    },
  } as { [key: string]: APIConf },
};

export async function GET(req: NextRequest) {
  const GET_HANDLERS = HANDLERS.GET;
  const apiKey = req.nextUrl.pathname.replace('/api/front', '');

  const targetApiKey = Object.keys(GET_HANDLERS).find(key => {
    const isMatched = key.endsWith('/*')
      ? apiKey.startsWith(key.replace('/*', ''))
      : [apiKey + '/', apiKey].includes(key);
    return isMatched;
  });

  let apiConf = GET_HANDLERS[targetApiKey ?? ''] as APIConf;

  if (!apiConf) {
    return NextResponse.json({ error: 'API not found' }, { status: 404 });
  }

  let isPrivateProductsApi = false;
  if (apiKey === '/end/products') {
    const token = req.cookies.get('token')?.value ?? '';
    const hasLoginHead = req.headers.get('X-Has-Login');
    const referHead = req.headers.get('referer');
    const hasLogin = hasLoginHead ? hasLoginHead === 'true' : false;

    // if has login , but no token cookie, go login page
    if (hasLogin && !token) {
      return NextResponse.json(
        {
          success: false,
          message: 'Unauthorized',
          data: { action: 'LOGIN', returnUrl: referHead },
        },
        {
          status: 401,
        }
      );
    }
    // has login and has token
    // or
    // not login but no token
    const realApiKey = !token ? apiConf.publicAPI : apiConf.privateAPI;
    isPrivateProductsApi = realApiKey === apiConf.privateAPI;
    apiConf = GET_HANDLERS[realApiKey!] || GET_HANDLERS[realApiKey + '/'];
  }

  // if (apiKey.match('/v2/countries')) {
  //   apiConf = GET_HANDLERS['/v2/countries'];
  //   apiConf.api = apiKey;
  // }

  // if (apiKey.match('/product/detail')) {
  //   apiConf = GET_HANDLERS['/product/detail'];
  //   apiConf.api = '/v2/products' + apiKey.replace('/product/detail', '');
  //   let isProductDetailApi = false;
  //   isProductDetailApi = true;
  // }

  const domain = apiConf.domain || DSZ_API_DOMAIN;
  let api = apiConf.api || apiKey;
  if (targetApiKey?.endsWith('/*')) {
    api = apiKey.replace(targetApiKey.slice(0, -2), api.replace(/\/$/, ''));
  }

  const handler =
    apiConf.handler ||
    getHandler(api, domain, apiConf.dataCallback, apiConf.errorCallback);
  const res = (await handler(req)) as APIRes;

  if (apiConf.needLogin) {
    if (!res.success && res.data.status * 1 === 401) {
      return NextResponse.json(
        {
          success: false,
          message: 'Unauthorized',
          data: { action: 'LOGIN' },
        },
        {
          status: 401,
        }
      );
    }
  }

  return NextResponse.json(res);
}

export async function POST(req: NextRequest) {
  const POST_HANDLERS = HANDLERS.POST;
  const apiKey = req.nextUrl.pathname.replace('/api/front', '');
  const apiConf = POST_HANDLERS[apiKey];
  if (!apiConf) {
    return NextResponse.json({ error: 'API not found' }, { status: 404 });
  }

  const domain = apiConf.domain || DSZ_API_DOMAIN;
  const api = apiConf.api || apiKey;
  const handler =
    apiConf.handler || postHandler(api, domain, apiConf.dataCallback);
  const res = await handler(req);

  return NextResponse.json(res);
}
